package com.elmcode.server.controller.app;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.OpenApiRoyaltyDetailInfoPojo;
import com.alipay.api.domain.RefundGoodsDetail;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.elmcode.server.elmenum.OrderStatusEnum;
import com.elmcode.server.elmenum.PayStatusEnum;
import com.elmcode.server.entity.BookEntity;
import com.elmcode.server.exception.BusException;
import com.elmcode.server.exception.ParamsException;
import com.elmcode.server.properties.AliPayProperties;
import com.elmcode.server.service.BookService;
import com.elmcode.server.utils.JSONUtil;
import com.elmcode.server.utils.Result;
import com.elmcode.server.websocket.WebSocketServer;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;

@Slf4j
@RestController
@Api(tags = "支付接口")
@RequestMapping
public class PayController {

    @Resource
    AliPayProperties aliPayProperties;

    @Autowired
    BookService bookService;

    @Autowired
    AlipayClient alipayClient;

    @Autowired
    WebSocketServer webSocketServer;

    private String trade_no;


    /**
     * 调用支付宝支付页面的方法
     * @param num
     * @return
     */
    @GetMapping("app/pay")
    public Result payAli(String payWay,String num){

        //TODO 判断是否超时。。。

        if(payWay.equals(PayStatusEnum.PAY_METHOD_ZHIFUBAO.getMsg())){
            //支付方式为：支付宝
            AlipayTradeWapPayRequest alipayRequest =new AlipayTradeWapPayRequest();//创建API对应的request

            alipayRequest.setReturnUrl(aliPayProperties.getReturnUrl());
            alipayRequest.setNotifyUrl(aliPayProperties.getNotifyUrl());

            //TODO 获取当前商品的价格
            BookEntity byNum = bookService.getOrderByNum(num);
            //准备参数信息
            Map<String,Object> payParam = new HashMap<>();
            String productName="TEST"; //测试商品
            if(byNum != null && byNum.getStatus().equals(OrderStatusEnum.PENDING_PAYMENT.getCode())){
                //TODO 支付方式--支付宝
                byNum.setPayMethod(PayStatusEnum.PAY_METHOD_ZHIFUBAO.getCode());//更新 支付方式
                this.bookService.updateByNum(byNum);
                //设置 订单号 和 价格
                payParam.put("out_trade_no",num);//订单号
                payParam.put("total_amount",byNum.getAmount());//支付金额
                payParam.put("subject",productName);
                payParam.put("timeout_express",aliPayProperties.getTimeout());
                payParam.put("product_code","QUICK_WAP_PAY");//TODO 移动端特有的
                try {
                    String payParamInfo = JSON.toJSONString(payParam);
                    //String payParamInfo = JSONUtil.mapToJson(payParam);
                    alipayRequest.setBizContent(payParamInfo);
                    //向支付宝服务器发请求
                    String result = alipayClient.pageExecute(alipayRequest).getBody();
                    return Result.ok("支付成功",result);
                } catch (AlipayApiException e) {
                    e.printStackTrace();
                    throw new BusException("支付失败");
                }

            }else {
                throw new ParamsException("参数异常");
            }
        }else if(payWay.equals(PayStatusEnum.PAY_METHOD_WEIXIN.getMsg())){
            //TODO 微信支付
        }else {
            throw new BusException("没有对应的支付方式，请检查!");
        }
        return null;
    }

    //通知
       //当手机端支付成功之后,支付宝服务器会调用该地址,告诉指定订单支付成功，那么这里接口就要处理相关的业务逻辑
           //比如:设置订单支付状态

    /**
     * 支付宝支付成功或者失败的回调方法---异步请求
     * @param request
     * @return
     * @throws UnsupportedEncodingException
     */
    @PostMapping("pay/ali/notify")
    public String aliWapPay(HttpServletRequest request) throws UnsupportedEncodingException {
        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
            try {
                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            params.put(name, valueStr);
        }
        boolean signVerified = false; //调用SDK验证签名
        try {
            signVerified = AlipaySignature.rsaCheckV1(params, aliPayProperties.getAlipayPublicKey(), aliPayProperties.getCharset(), aliPayProperties.getSignType());
        } catch (Exception e) {
            e.printStackTrace();
        }

        if(signVerified) {//验证成功
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //支付宝交易号
            trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
            log.info("交易状态.........{}",trade_status);
           if(trade_status.equals("TRADE_SUCCESS")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //如果有做过处理，不执行商户的业务程序

                //注意：
                //付款完成后，支付宝系统发送该交易状态通知
               BookEntity order = bookService.getOrderByNum(out_trade_no);
               if((order.getPayStatus().equals(PayStatusEnum.PAY_STATUS_YES.getCode())
                  && order.getStatus().equals(OrderStatusEnum.PENDING_CONFIRMED.getCode()))
                       //支付完成之后
                ){

                   return "success";
               }

               if((order.getStatus().equals(OrderStatusEnum.REFUNDED.getCode())
                       && order.getPayStatus().equals(PayStatusEnum.PAY_STATUS_CANCEL.getCode()))) {
                   //退款之后  不可以支付
                   return "fail";
               }
               // TODO 发送订单成功语音通知
               Map<String, String> map = new HashMap<>();
               map.put("type", "createBook");
               map.put("num", out_trade_no);
               String data = null;
               try {
                   data = JSONUtil.mapToJson(map);
                   // TODO 发送订单消息 “订单来了，请及时查收！”
                   webSocketServer.sendToClient("laomou", data);
               } catch (JsonProcessingException e) {
                   e.printStackTrace();
               }

               // TODO  修改数据库中out_trade_no订单的支付状态为已经支付
               order.setPayStatus(PayStatusEnum.PAY_STATUS_YES.getCode());//支付状态
               order.setPayTime(new Date());
               order.setStatus(OrderStatusEnum.PENDING_CONFIRMED.getCode());//订单状态
               bookService.updateByNum(order);

           }
            return "success";
        }else {//验证失败
            return "fail";
            //调试用，写文本函数记录程序运行情况是否正常
            //String sWord = AlipaySignature.getSignCheckContentV1(params);
            //AlipayConfig.logResult(sWord);
        }
    }

    /**
     * 支付退款
     * @param orderNumber  订单号
     * @param refundAmount  退款金额
     * @return
     * @throws IOException
     * @throws AlipayApiException
     */
    @ApiOperation("退款接口")
    @GetMapping("refund")
    public Result refund(String orderNumber, String refundAmount) throws IOException, AlipayApiException {
        // 初始化SDK
        AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());

        // 构造请求参数以调用接口
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();

        BookEntity order = bookService.getOrderByNum(orderNumber);

        if(order != null){
            // 设置商户订单号
            model.setOutTradeNo(orderNumber);

            // 设置查询选项
            List<String> queryOptions = new ArrayList<String>();
            queryOptions.add("refund_detail_item_list");
            model.setQueryOptions(queryOptions);

            // 设置退分账明细信息
            List<OpenApiRoyaltyDetailInfoPojo> refundRoyaltyParameters = new ArrayList<OpenApiRoyaltyDetailInfoPojo>();
            OpenApiRoyaltyDetailInfoPojo refundRoyaltyParameters0 = new OpenApiRoyaltyDetailInfoPojo();
            refundRoyaltyParameters0.setAmount(order.getAmount().toString());
            refundRoyaltyParameters0.setTransIn("2088101126708402");
            refundRoyaltyParameters0.setRoyaltyType("transfer");
            refundRoyaltyParameters0.setTransOut("2088101126765726");
            refundRoyaltyParameters0.setTransOutType("userId");
            refundRoyaltyParameters0.setRoyaltyScene("达人佣金");
            refundRoyaltyParameters0.setTransInType("userId");
            refundRoyaltyParameters0.setTransInName(order.getCustomerName());
            refundRoyaltyParameters0.setDesc("分账给2088101126708402");
            refundRoyaltyParameters.add(refundRoyaltyParameters0);
            model.setRefundRoyaltyParameters(refundRoyaltyParameters);

            // 设置支付宝交易号
            model.setTradeNo(trade_no);

            // 设置退款金额
            model.setRefundAmount(refundAmount);

            // 设置退款包含的商品列表信息
            List<RefundGoodsDetail> refundGoodsDetail = new ArrayList<RefundGoodsDetail>();
            RefundGoodsDetail refundGoodsDetail0 = new RefundGoodsDetail();
            refundGoodsDetail0.setOutSkuId("outSku_01");
            refundGoodsDetail0.setOutItemId("outItem_01");
            refundGoodsDetail0.setGoodsId("apple-01");
            refundGoodsDetail0.setRefundAmount(order.getAmount().toString());
            refundGoodsDetail.add(refundGoodsDetail0);
            model.setRefundGoodsDetail(refundGoodsDetail);

            // 设置退款原因说明
            model.setRefundReason("正常退款");

            // 设置针对账期交易
            model.setRelatedSettleConfirmNo("2024041122001495000530302869");

            // 设置退款请求号
            model.setOutRequestNo("HZ01RF001");

            request.setBizModel(model);
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            System.out.println(response.getBody());

            if (response.isSuccess()) {
                System.out.println("调用成功");

                //TODO 设置订单状态
                order.setStatus(OrderStatusEnum.REFUNDED.getCode());
                order.setPayStatus(PayStatusEnum.PAY_STATUS_CANCEL.getCode());

                bookService.updateByNum(order);

                return Result.ok("退款成功");
            } else {
                System.out.println("调用失败");
                // sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
                // String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
                // System.out.println(diagnosisUrl);
                return Result.error("退款失败");
            }

        }else {
            throw new BusException("订单号错误");
        }
    }

    private AlipayConfig getAlipayConfig() {
        String privateKey  = aliPayProperties.getMerchantPrivateKey();
        String alipayPublicKey = aliPayProperties.getAlipayPublicKey();
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl(aliPayProperties.gatewayUrl);
        alipayConfig.setAppId(aliPayProperties.getAppId());
        alipayConfig.setPrivateKey(privateKey);
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        alipayConfig.setCharset("UTF-8");
        alipayConfig.setSignType("RSA2");
        return alipayConfig;
    }

}
